package cn.iocoder.an.module.mold.service.category;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.an.module.business.dal.dataobject.equipmenttype.EquipmentTypeDO;
import cn.iocoder.an.module.mold.controller.admin.drawingno.vo.DrawingNoImportExcelVO;
import cn.iocoder.an.module.mold.dal.dataobject.drawingno.DrawingNoDO;
import cn.iocoder.an.module.mold.utils.ImportRespVO;
import io.micrometer.common.util.StringUtils;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

import cn.iocoder.an.module.mold.controller.admin.category.vo.*;
import cn.iocoder.an.module.mold.dal.dataobject.category.CategoryDO;
import cn.iocoder.an.framework.common.pojo.PageResult;
import cn.iocoder.an.framework.common.pojo.PageParam;
import cn.iocoder.an.framework.common.util.object.BeanUtils;

import cn.iocoder.an.module.mold.dal.mysql.category.CategoryMapper;

import static cn.iocoder.an.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.an.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.an.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.an.module.business.enums.ErrorCodeConstants.EQUIPMENT_TYPE_NOT_EXISTS;
import static cn.iocoder.an.module.mold.enums.ErrorCodeConstants.*;

/**
 * 模具类型 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class CategoryServiceImpl implements CategoryService {

    @Resource
    private CategoryMapper categoryMapper;

    @Override
    public Long createCategory(CategorySaveReqVO createReqVO) {
        // 校验父id的有效性
        validateParentCategory(null, createReqVO.getParentId());
        // 校验类型编码的唯一性
        validateCategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getCode());

        // 插入
        CategoryDO category = BeanUtils.toBean(createReqVO, CategoryDO.class);
        categoryMapper.insert(category);

        // 返回
        return category.getId();
    }

    @Override
    public void updateCategory(CategorySaveReqVO updateReqVO) {
        // 校验存在
        validateCategoryExists(updateReqVO.getId());
        // 校验父id的有效性
        validateParentCategory(updateReqVO.getId(), updateReqVO.getParentId());
        // 校验类型名称的唯一性
        validateCategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getCode());

        // 更新
        CategoryDO updateObj = BeanUtils.toBean(updateReqVO, CategoryDO.class);
        categoryMapper.updateById(updateObj);
    }

    @Override
    public void deleteCategory(Long id) {
        // 校验存在
        validateCategoryExists(id);
        // 校验是否有子模具类型
        if (categoryMapper.selectCountByParentId(id) > 0) {
            throw exception(CATEGORY_EXITS_CHILDREN);
        }
        // 删除
        categoryMapper.deleteById(id);
    }


    private void validateCategoryExists(Long id) {
        if (categoryMapper.selectById(id) == null) {
            throw exception(CATEGORY_NOT_EXISTS);
        }
    }

    private void validateParentCategory(Long id, Long parentId) {
        if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) {
            return;
        }
        // 1. 不能设置自己为父模具类型
        if (Objects.equals(id, parentId)) {
            throw exception(CATEGORY_PARENT_ERROR);
        }
        // 2. 父模具类型不存在
        CategoryDO parentCategory = categoryMapper.selectById(parentId);
        if (parentCategory == null) {
            throw exception(CATEGORY_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父模具类型，如果父模具类型是自己的子模具类型，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentId = parentCategory.getParentId();
            if (Objects.equals(id, parentId)) {
                throw exception(CATEGORY_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父模具类型
            if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) {
                break;
            }
            parentCategory = categoryMapper.selectById(parentId);
            if (parentCategory == null) {
                break;
            }
        }
    }

    private void validateCategoryNameUnique(Long id, Long parentId, String code) {
        //不在同一父级目录
         CategoryDO category = categoryMapper.selectByCode( code);
      //  CategoryDO category = categoryMapper.selectByParentIdAndCode(parentId, code);
        if (category == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的模具类型
        if (id == null) {
            throw exception(CATEGORY_NAME_DUPLICATE);
        }
        if (!Objects.equals(category.getId(), id)) {
            throw exception(CATEGORY_NAME_DUPLICATE);
        }
    }

    @Override
    public CategoryDO getCategory(Long id) {
        return categoryMapper.selectById(id);
    }

    @Override
    public List<CategoryDO> getCategoryList(CategoryListReqVO listReqVO) {
        return categoryMapper.selectList(listReqVO);
    }

    @Override
    public List<CategoryDO> getCategoryAll() {
        return categoryMapper.selectList();
    }

    @Override
    public Long getCategoryIdByCode(String code) {
        CategoryDO categoryDO = categoryMapper.selectFirstOne(
                CategoryDO::getCode, code
        );
        if (categoryDO != null) {
            return categoryDO.getId();
        } else {
            throw exception(CATEGORY_NOT_EXISTS);
        }
    }

    @Override
    public CategoryDO getCategoryByCode(String code) {
        CategoryDO categoryDO = categoryMapper.selectFirstOne(
                CategoryDO::getCode, code
        );
        if (categoryDO != null) {
            return categoryDO;
        } else {
            throw exception(CATEGORY_NOT_EXISTS);
        }
    }


    @Override
    public ImportRespVO importCategoryList(List<CategoryImportExcelVO> iomportCategory, boolean isUpdateSupport) {
        if (CollUtil.isEmpty(iomportCategory)) {
            throw exception(CATEGORY_NOT_EXISTS);
        }

        ImportRespVO respVO = ImportRespVO.builder().insertNameList(new ArrayList<>())
                .updateNameList(new ArrayList<>()).failureMap(new LinkedHashMap<>()).build();
        AtomicInteger count = new AtomicInteger(1);
        iomportCategory.forEach(item -> {
            count.incrementAndGet();//记录行号
            // 2.1.1 校验编码
            if (StringUtils.isEmpty(item.getCode())) {
                return;
            }

            // 2.1.2 校验名称
            if (StringUtils.isEmpty(item.getName())) {
                respVO.getFailureMap().put(item.getCode(), "名称不能为空!");
                return;
            }

            // 2.1.4 校验父级编码
            if (StringUtils.isEmpty(item.getParentCode())) {
                //设置父Id为0
                item.setParentId(0L);
            }else{
                if (item.getParentCode().equals(item.getCode())) {
                    respVO.getFailureMap().put(item.getCode(), "父级编码不能为自身!");
                    return;
                }

                try {
                    CategoryDO parentCat = getCategoryByCode(item.getParentCode());
                    item.setParentId(parentCat.getId());
                } catch (Exception e) {
                    respVO.getFailureMap().put(item.getCode(), e.getMessage());
                    return;
                }
            }

            //更新或者插入
            //判断图号是否重复
            String code = item.getCode();
            CategoryDO exists = categoryMapper.selectFirstOne(
                    CategoryDO::getCode, code
            );
            if (exists != null) {
                if (isUpdateSupport) {
                    //允许更新
                    //设置ID
                    item.setId(exists.getId());
                    CategoryDO categoryDO = BeanUtils.toBean(item, CategoryDO.class);
                    categoryMapper.updateById(categoryDO);
                    respVO.getUpdateNameList().add(item.getCode());
                } else {
                    respVO.getFailureMap().put(item.getCode(), CATEGORY_NAME_DUPLICATE.getMsg());
                }
            } else {
                categoryMapper.insert(BeanUtils.toBean(item, CategoryDO.class));
                respVO.getInsertNameList().add(item.getCode());
            }
        });
        return respVO;

    }


}